mvcc database space exceeded 报错

etcd在运行过程中出现”mvcc: database space exceeded”报错问题

1 、问题描述: 在新版etcd运行的过程中,日志中出现这种异常日志

1
"mvcc: database space exceeded"

经查是因为etcd存储超限制造成的,超限的原因是因为 etcd 持续记录它的键空间的确切历史,每变更一次键值都会保留一份记录,以至于etcd的存储空间被不断消耗。具体可参考https://alexstocks.github.io/html/etcd.html 4.4.1 MVCC介绍

2、原因分析:

  • etcd服务未设置自动压缩参数(auto-compact)
  • etcd 默认不会自动 compact,需要设置启动参数,或者通过命令进行compact,如果变更频繁建议设置,否则会导致空间和内存的浪费以及错误。Etcd v3 的默认的 backend quota 2GB,如果不 compact,boltdb 文件大小超过这个限制后,就会报错:”Error: etcdserver: mvcc: database space exceeded”,导致数据无法写入

etcd可通过存储空间的配额来控制键空间大小,,默认配置的大小是2G.
可在启动时通过参数 –quota-backend-bytes 来指定

1
2
# 设置非常小的 16MB 配额
$ etcd --quota-backend-bytes=16777216

以下是在42上查到的情况,可发现已经没有键空间了

1
2
3
4
5
6
7
8
9
10
cloud@42 bin]$  ETCDCTL_API=3  etcdctl --write-out=table endpoint status  --endpoints=ip1:12379
+---------------------+------------------+---------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+---------------------+------------------+---------+---------+-----------+-----------+------------+
| ip1:12379 | 68c241a246b24e34 | 3.2.22 | 2.1 GB | false | 342 | 17850109 |
+---------------------+------------------+---------+---------+-----------+-----------+------------+
[cloud@42 bin]$ ETCDCTL_API=3 etcdctl alarm list --endpoints=ip1:12379
memberID:5517845181538471708 alarm:NOSPACE
memberID:1531360066298200737 alarm:NOSPACE
memberID:7548668090652970548 alarm:NOSPACE

3、初步解决方法:因为 etcd 保持它的键空间的确切历史,这个历史应该定期压缩来避免性能下降和最终的存储空间枯竭。压缩键空间历史删除所有关于被废弃的在给定键空间修订版本之前的键的信息。这些key使用的空间随机变得可用来继续写入键空间。
后台手工可采用以下脚本压缩清理掉(集群内机器都要执行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1 #!/bin/bash
2 IP=`ip a show dev eth0|grep -w inet|awk '{print $2}'|awk -F '/' '{print $1}'`
3 #IP=127.0.0.1
4 PORT=12379
5 HOST=$IP:$PORT
6
7 #使用API3
8 export ETCDCTL_API=3
9 # 查看告警信息,告警信息一般 memberID:8630161756594109333 alarm:NOSPACE
10 etcdctl --endpoints=http://${HOST} alarm list
11
12 # 获取当前版本
13 rev=$(etcdctl --endpoints=http://${HOST} endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*')
14 # 压缩掉所有旧版本
15 etcdctl --endpoints=http://${HOST} compact $rev
16 # 整理多余的空间
17 etcdctl --endpoints=http://${HOST} defrag
18 sleep 2
19
20 # 取消告警信息
21 etcdctl --endpoints=http://${HOST} alarm disarm
22

最终方法: 清理后内存还是会不断增长,需要在启动时加入 –auto-compaction-retention=1 时间参数可以自行设定

1
2
# 保持一个小时的历史
$ etcd --auto-compaction-retention=1

详细可参考
https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/maintenance.md#space-quota

线上etcd运行参数为:

1
2
etcd --name infra1 --data-dir=/home/s/var/etcd/infra --listen-client-urls http://ip1:12379 --advertise-client-urls http://ip1:12379 --listen-peer-urls http://ip1:12380 --initial-advertise-peer-urls http://ip1:12380 --initial-cluster-token etcd-cluster-1 --initial-cluster infra1=http://ip1:12380,infra2=http://ip2:12380,infra3=http://ip3:12380 --auto-compaction-retention=1 --initial-cluster-state new

该参数会自动每隔一个小时自动压缩键空间,配置后经观察etcd内存还是会增长,然后最终稳定,在42 43 44 上经过一天的运行后最终在默认配置2G内存的情况下稳定在七百多兆。

1
2
3
4
5
6
7
[cloud@42 bin]$  ETCDCTL_API=3  etcdctl --write-out=table endpoint status  --endpoints=ip1:12379
+---------------------+------------------+---------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+---------------------+------------------+---------+---------+-----------+-----------+------------+
| ip1:12379 | 68c241a246b24e34 | 3.2.22 | 757 MB | true | 358 | 81169018 |
+---------------------+------------------+---------+---------+-----------+-----------+------------+